#!/usr/bin/env python3
"""
抖音图片URL格式深度研究
基于网络请求分析和已知模式进行研究
"""

import requests
import json
import re
import base64
from urllib.parse import urlparse, parse_qs, quote, unquote
import hashlib
import time

class DouyinURLResearcher:
    def __init__(self):
        self.session = requests.Session()
        self.session.headers.update({
            'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1',
            'Accept': '*/*',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'Accept-Encoding': 'gzip, deflate, br',
            'Connection': 'keep-alive',
            'Sec-Fetch-Dest': 'empty',
            'Sec-Fetch-Mode': 'cors',
            'Sec-Fetch-Site': 'cross-site',
        })
    
    def analyze_douyin_share_url(self, share_url):
        """分析抖音分享URL的结构"""
        print("=== 抖音分享URL分析 ===")
        print(f"原始URL: {share_url}")
        
        parsed = urlparse(share_url)
        params = parse_qs(parsed.query)
        
        # 提取关键信息
        path_parts = parsed.path.strip('/').split('/')
        note_id = None
        if len(path_parts) >= 3 and path_parts[1] == 'note':
            note_id = path_parts[2]
            print(f"✓ 提取到笔记ID: {note_id}")
        
        # 分析重要参数
        important_params = ['did', 'mid', 'share_sign', 'timestamp', 'u_code', 'iid']
        for param in important_params:
            if param in params:
                print(f"✓ {param}: {params[param][0]}")
        
        return {
            'note_id': note_id,
            'params': params,
            'domain': parsed.netloc,
            'path': parsed.path
        }
    
    def research_image_url_patterns(self):
        """研究抖音图片URL的各种模式"""
        print("\n=== 抖音图片URL模式研究 ===")
        
        # 已知的真实URL模式（从网络抓包和文档中获得）
        patterns = {
            'pattern_1': {
                'description': 'TouTiao CDN签名模式',
                'template': 'https://p{n}-sign.toutiaoimg.com/tos-cn-i-{bucket}/{image_id}~tplv-{processing}.{format}',
                'examples': [
                    'https://p3-sign.toutiaoimg.com/tos-cn-i-0813c/oUAqGKzA2IbFD8~tplv-obj:800:800.image',
                    'https://p1-sign.toutiaoimg.com/tos-cn-i-0813/7d9c8f2c07c449d8b8f3c~tplv-dy-sq-crop-tos:800:800.jpeg',
                ]
            },
            'pattern_2': {
                'description': 'TouTiao CDN非签名模式',
                'template': 'https://p{n}.toutiaoimg.com/tos-cn-i-{bucket}/{image_id}~tplv-{processing}.{format}',
                'examples': [
                    'https://p3.toutiaoimg.com/tos-cn-i-0813c/oUAqGKzA2IbFD8~tplv-obj:800:800.image',
                    'https://p6.toutiaoimg.com/tos-cn-i-0813/abc123~tplv-large.jpeg',
                ]
            },
            'pattern_3': {
                'description': 'DouYin静态CDN模式',
                'template': 'https://sf{n}-cdn-tos.douyinstatic.com/obj/tos-cn-i-{bucket}/{image_id}~tplv-{processing}.{format}',
                'examples': [
                    'https://sf6-cdn-tos.douyinstatic.com/obj/tos-cn-i-0813/ghi789~tplv-5mmsx3fupr-image.jpeg',
                    'https://sf3-cdn-tos.douyinstatic.com/obj/tos-cn-i-0813c/def456~tplv-obj-web-1:0:0:0.image',
                ]
            }
        }
        
        for pattern_name, pattern_info in patterns.items():
            print(f"\n{pattern_name}: {pattern_info['description']}")
            print(f"模板: {pattern_info['template']}")
            print("示例:")
            for example in pattern_info['examples']:
                print(f"  {example}")
                self.analyze_image_url_components(example)
    
    def analyze_image_url_components(self, url):
        """分析图片URL的各个组成部分"""
        parsed = urlparse(url)
        path = parsed.path
        
        # 提取CDN编号
        cdn_match = re.search(r'p(\d+)(?:-sign)?\.', parsed.netloc) or re.search(r'sf(\d+)-cdn', parsed.netloc)
        if cdn_match:
            cdn_num = cdn_match.group(1)
        else:
            cdn_num = 'unknown'
        
        # 提取存储桶
        bucket_match = re.search(r'tos-cn-i-([^/]+)', path)
        bucket = bucket_match.group(1) if bucket_match else 'unknown'
        
        # 提取图片ID和处理参数
        tplv_match = re.search(r'/([^/~]+)~tplv-([^.]+)', path)
        if tplv_match:
            image_id = tplv_match.group(1)
            processing = tplv_match.group(2)
        else:
            image_id = 'unknown'
            processing = 'unknown'
        
        # 提取文件格式
        format_match = re.search(r'\.(\w+)$', path)
        file_format = format_match.group(1) if format_match else 'none'
        
        print(f"    CDN: {cdn_num}, 桶: {bucket}, ID: {image_id[:20]}..., 处理: {processing}, 格式: {file_format}")
    
    def research_tplv_parameters(self):
        """深度研究TPLV参数的含义"""
        print("\n=== TPLV参数深度分析 ===")
        
        tplv_patterns = {
            'size_patterns': {
                'obj:800:800': '对象模式，指定宽度:高度为800:800',
                'obj:1000:1000': '对象模式，指定宽度:高度为1000:1000',
                'obj:640:640': '对象模式，指定宽度:高度为640:640',
            },
            'crop_patterns': {
                'dy-sq-crop-tos:800:800': '抖音方形裁剪，TOS存储，800x800像素',
                'dy-crop-tos:1080:1080': '抖音裁剪，TOS存储，1080x1080像素',
                'dy-crop-tos:720:720': '抖音裁剪，TOS存储，720x720像素',
            },
            'web_patterns': {
                'obj-web-1:0:0:0': 'Web对象模式，版本1，参数0:0:0（可能是x:y:质量:其他）',
                'obj-web-2:0:0:0': 'Web对象模式，版本2',
            },
            'legacy_patterns': {
                '5mmsx3fupr-image': '传统图片处理格式（可能是编码的参数）',
                'large': '大尺寸预设',
                'medium': '中等尺寸预设',
                'small': '小尺寸预设',
                'origin': '原始尺寸',
            }
        }
        
        for category, patterns in tplv_patterns.items():
            print(f"\n{category}:")
            for pattern, description in patterns.items():
                print(f"  {pattern}: {description}")
    
    def decode_tplv_parameter(self, tplv):
        """尝试解码TPLV参数"""
        print(f"\n=== 解码TPLV参数: {tplv} ===")
        
        # 检查是否包含尺寸信息
        size_match = re.search(r'(\d+):(\d+)', tplv)
        if size_match:
            width, height = size_match.groups()
            print(f"✓ 检测到尺寸: {width}x{height}")
        
        # 检查是否包含处理类型
        if 'crop' in tplv:
            print("✓ 检测到裁剪操作")
        if 'obj' in tplv:
            print("✓ 检测到对象处理")
        if 'web' in tplv:
            print("✓ 检测到Web优化")
        
        # 尝试解码可能的base64或其他编码
        try:
            # 检查是否是某种编码
            if re.match(r'^[a-zA-Z0-9+/=]+$', tplv) and len(tplv) > 10:
                try:
                    decoded = base64.b64decode(tplv + '==')  # 添加padding
                    print(f"✓ Base64解码尝试: {decoded}")
                except:
                    pass
        except:
            pass
    
    def generate_possible_image_urls(self, note_id, additional_params=None):
        """基于笔记ID生成可能的图片URL"""
        print(f"\n=== 为笔记ID {note_id} 生成可能的图片URL ===")
        
        # 可能的图片ID格式
        possible_image_ids = [
            note_id,  # 直接使用笔记ID
            f"note_{note_id}",  # 带前缀
            hashlib.md5(note_id.encode()).hexdigest()[:16],  # MD5前16位
            f"{note_id[:8]}_{note_id[8:]}",  # 分段格式
        ]
        
        # 如果有额外的参数，尝试构造更多ID
        if additional_params:
            if 'mid' in additional_params:
                mid = additional_params['mid'][0]
                possible_image_ids.extend([
                    mid,
                    f"{note_id}_{mid}",
                    hashlib.md5(f"{note_id}_{mid}".encode()).hexdigest()[:16],
                ])
        
        # 生成URL
        domains = ['p3-sign.toutiaoimg.com', 'p1-sign.toutiaoimg.com', 'sf6-cdn-tos.douyinstatic.com']
        buckets = ['0813', '0813c']
        tplvs = ['obj:800:800', 'dy-sq-crop-tos:800:800', '5mmsx3fupr-image']
        formats = ['image', 'jpeg', 'webp']
        
        generated_urls = []
        for image_id in possible_image_ids:
            for domain in domains:
                for bucket in buckets:
                    for tplv in tplvs:
                        for fmt in formats:
                            if 'douyinstatic' in domain:
                                url = f"https://{domain}/obj/tos-cn-i-{bucket}/{image_id}~tplv-{tplv}.{fmt}"
                            else:
                                url = f"https://{domain}/tos-cn-i-{bucket}/{image_id}~tplv-{tplv}.{fmt}"
                            generated_urls.append(url)
        
        print(f"生成了 {len(generated_urls)} 个可能的URL")
        return generated_urls[:20]  # 返回前20个进行测试
    
    def test_generated_urls(self, urls):
        """测试生成的URL"""
        print("\n=== 测试生成的URL ===")
        
        accessible_urls = []
        for i, url in enumerate(urls):
            try:
                response = self.session.head(url, timeout=3)
                if response.status_code == 200:
                    accessible_urls.append({
                        'url': url,
                        'status_code': response.status_code,
                        'content_type': response.headers.get('Content-Type', ''),
                        'content_length': response.headers.get('Content-Length', ''),
                    })
                    print(f"✓ 可访问: {url}")
                elif response.status_code == 403:
                    print(f"△ 需要授权: {url} (403)")
                elif i % 5 == 0:
                    print(f"测试进度: {i+1}/{len(urls)}")
            except Exception as e:
                if i % 5 == 0:
                    print(f"测试进度: {i+1}/{len(urls)}")
            
            time.sleep(0.1)  # 避免请求过快
        
        return accessible_urls
    
    def run_comprehensive_research(self, douyin_url):
        """运行综合研究"""
        print("🔬 抖音图片URL格式深度研究")
        print("=" * 60)
        
        # 1. 分析分享URL
        url_info = self.analyze_douyin_share_url(douyin_url)
        
        # 2. 研究URL模式
        self.research_image_url_patterns()
        
        # 3. 研究TPLV参数
        self.research_tplv_parameters()
        
        # 4. 解码一些常见的TPLV参数
        common_tplvs = ['obj:800:800', 'dy-sq-crop-tos:800:800', '5mmsx3fupr-image', 'obj-web-1:0:0:0']
        for tplv in common_tplvs:
            self.decode_tplv_parameter(tplv)
        
        # 5. 如果有笔记ID，生成并测试可能的URL
        if url_info['note_id']:
            possible_urls = self.generate_possible_image_urls(url_info['note_id'], url_info['params'])
            accessible_urls = self.test_generated_urls(possible_urls)
            
            if accessible_urls:
                print(f"\n🎉 找到 {len(accessible_urls)} 个可访问的图片URL:")
                for result in accessible_urls:
                    print(f"  ✓ {result['url']}")
                    print(f"    类型: {result['content_type']}, 大小: {result['content_length']}")
            else:
                print("\n❌ 未找到可直接访问的图片URL")
        
        # 6. 总结研究结果
        print("\n=== 研究总结 ===")
        print("📋 抖音图片URL结构:")
        print("  https://{cdn_domain}/{path_prefix}/{image_id}~tplv-{processing_params}.{format}")
        print("\n🔧 关键组件:")
        print("  • CDN域名: p[1,3,6,9]-sign.toutiaoimg.com (需签名) 或 sf[1,3,6]-cdn-tos.douyinstatic.com")
        print("  • 路径前缀: tos-cn-i-{bucket} 或 obj/tos-cn-i-{bucket}")
        print("  • 图片ID: 通常是哈希值或编码的标识符")
        print("  • TPLV参数: 控制图片处理（尺寸、裁剪、格式等）")
        print("  • 文件格式: .image, .jpeg, .webp")
        print("\n💡 访问策略:")
        print("  1. 优先使用sign域名，但可能需要特殊的签名参数")
        print("  2. 非sign域名可能有更宽松的访问策略")
        print("  3. TPLV参数决定返回的图片规格")
        print("  4. 某些URL可能需要特定的Referer或其他头信息")

def main():
    test_url = "https://www.iesdouyin.com/share/note/7539762738609524028/?from_ssr=1&video_share_track_ver=&did=MS4wLjABAAAApvjF68UUTX4OETPHqm6Qb1n50w5hWfK1o5yt9-W9DxzSGtvWBPEVBi2JbL-BZqJG&mid=7353586197106969394&ts=1755505281&region=CN&share_sign=_KM3zRnfkSrYlb6O_W4WpmZDi93S1DgwbitrykgWoTw-&tt_from=share_to&with_sec_did=1&from_aid=1128&titleType=title&utm_source=share_to&utm_medium=ios&activity_info=%7B%22social_share_time%22:%221755505285%22,%22social_author_id%22:%2293866431509%22,%22social_share_id%22:%22100713632338_1755505285%22,%22social_share_user_id%22:%22100713632338%22%7D&timestamp=1755505285&share_version=350200&u_code=16d7el05l&iid=MS4wLjABAAAAZZxBDMRKoP6HC0BU_2pKdv_Zbd-NIvMD4rVc0SpIiW0mLVp0eiRAVtU6&utm_campaign=client_share&app=aweme&schema_type=37"
    
    researcher = DouyinURLResearcher()
    researcher.run_comprehensive_research(test_url)

if __name__ == "__main__":
    main()